"""
数据仓库基类

提供通用的数据访问模式和CRUD操作。
"""

from typing import TypeVar, Generic, List, Optional, Dict, Any, Type
from abc import ABC, abstractmethod

from sqlalchemy.orm import Session
from sqlalchemy import and_, or_, desc, asc, func

from src.models.base import BaseModel
from .manager import get_session

T = TypeVar('T', bound=BaseModel)


class BaseRepository(Generic[T], ABC):
    """
    数据仓库基类
    
    提供通用的CRUD操作和查询方法。
    """
    
    def __init__(self, model_class: Type[T]):
        self.model_class = model_class
    
    def get_session(self) -> Session:
        """获取数据库会话"""
        return get_session()
    
    def create(self, **kwargs) -> T:
        """创建新记录"""
        session = self.get_session()
        try:
            instance = self.model_class(**kwargs)
            session.add(instance)
            session.commit()
            session.refresh(instance)
            return instance
        except Exception as e:
            session.rollback()
            raise e
        finally:
            session.close()
    
    def create_from_dict(self, data: Dict[str, Any]) -> T:
        """从字典创建记录"""
        return self.create(**data)
    
    def get_by_id(self, id: int) -> Optional[T]:
        """根据ID获取记录"""
        session = self.get_session()
        try:
            return session.query(self.model_class).filter(self.model_class.id == id).first()
        finally:
            session.close()
    
    def get_all(self, limit: int = None, offset: int = None) -> List[T]:
        """获取所有记录"""
        session = self.get_session()
        try:
            query = session.query(self.model_class)
            
            if offset:
                query = query.offset(offset)
            if limit:
                query = query.limit(limit)
            
            return query.all()
        finally:
            session.close()
    
    def get_by_field(self, field_name: str, value: Any) -> List[T]:
        """根据字段值获取记录"""
        session = self.get_session()
        try:
            field = getattr(self.model_class, field_name)
            return session.query(self.model_class).filter(field == value).all()
        finally:
            session.close()
    
    def get_one_by_field(self, field_name: str, value: Any) -> Optional[T]:
        """根据字段值获取单条记录"""
        session = self.get_session()
        try:
            field = getattr(self.model_class, field_name)
            return session.query(self.model_class).filter(field == value).first()
        finally:
            session.close()
    
    def update(self, id: int, **kwargs) -> Optional[T]:
        """更新记录"""
        session = self.get_session()
        try:
            instance = session.query(self.model_class).filter(self.model_class.id == id).first()
            if instance:
                for key, value in kwargs.items():
                    if hasattr(instance, key):
                        setattr(instance, key, value)
                session.commit()
                session.refresh(instance)
            return instance
        except Exception as e:
            session.rollback()
            raise e
        finally:
            session.close()
    
    def update_from_dict(self, id: int, data: Dict[str, Any]) -> Optional[T]:
        """从字典更新记录"""
        session = self.get_session()
        try:
            instance = session.query(self.model_class).filter(self.model_class.id == id).first()
            if instance:
                instance.update_from_dict(data)
                session.commit()
                session.refresh(instance)
            return instance
        except Exception as e:
            session.rollback()
            raise e
        finally:
            session.close()
    
    def delete(self, id: int) -> bool:
        """删除记录"""
        session = self.get_session()
        try:
            instance = session.query(self.model_class).filter(self.model_class.id == id).first()
            if instance:
                session.delete(instance)
                session.commit()
                return True
            return False
        except Exception as e:
            session.rollback()
            raise e
        finally:
            session.close()
    
    def delete_by_field(self, field_name: str, value: Any) -> int:
        """根据字段值删除记录"""
        session = self.get_session()
        try:
            field = getattr(self.model_class, field_name)
            count = session.query(self.model_class).filter(field == value).count()
            session.query(self.model_class).filter(field == value).delete()
            session.commit()
            return count
        except Exception as e:
            session.rollback()
            raise e
        finally:
            session.close()
    
    def count(self, **filters) -> int:
        """统计记录数"""
        session = self.get_session()
        try:
            query = session.query(self.model_class)
            
            for field_name, value in filters.items():
                if hasattr(self.model_class, field_name):
                    field = getattr(self.model_class, field_name)
                    query = query.filter(field == value)
            
            return query.count()
        finally:
            session.close()
    
    def exists(self, **filters) -> bool:
        """检查记录是否存在"""
        return self.count(**filters) > 0
    
    def find(self, 
             filters: Dict[str, Any] = None,
             order_by: str = None,
             order_desc: bool = False,
             limit: int = None,
             offset: int = None) -> List[T]:
        """高级查询"""
        session = self.get_session()
        try:
            query = session.query(self.model_class)
            
            # 应用过滤条件
            if filters:
                for field_name, value in filters.items():
                    if hasattr(self.model_class, field_name):
                        field = getattr(self.model_class, field_name)
                        if isinstance(value, list):
                            query = query.filter(field.in_(value))
                        elif isinstance(value, dict):
                            # 支持范围查询
                            if 'gte' in value:
                                query = query.filter(field >= value['gte'])
                            if 'lte' in value:
                                query = query.filter(field <= value['lte'])
                            if 'gt' in value:
                                query = query.filter(field > value['gt'])
                            if 'lt' in value:
                                query = query.filter(field < value['lt'])
                            if 'like' in value:
                                query = query.filter(field.like(f"%{value['like']}%"))
                        else:
                            query = query.filter(field == value)
            
            # 应用排序
            if order_by and hasattr(self.model_class, order_by):
                field = getattr(self.model_class, order_by)
                if order_desc:
                    query = query.order_by(desc(field))
                else:
                    query = query.order_by(asc(field))
            
            # 应用分页
            if offset:
                query = query.offset(offset)
            if limit:
                query = query.limit(limit)
            
            return query.all()
        finally:
            session.close()
    
    def find_one(self, **filters) -> Optional[T]:
        """查找单条记录"""
        results = self.find(filters, limit=1)
        return results[0] if results else None
    
    def bulk_create(self, data_list: List[Dict[str, Any]]) -> List[T]:
        """批量创建记录"""
        session = self.get_session()
        try:
            instances = []
            for data in data_list:
                instance = self.model_class(**data)
                instances.append(instance)
                session.add(instance)
            
            session.commit()
            
            # 刷新所有实例以获取ID
            for instance in instances:
                session.refresh(instance)
            
            return instances
        except Exception as e:
            session.rollback()
            raise e
        finally:
            session.close()
    
    def bulk_update(self, updates: List[Dict[str, Any]]) -> int:
        """批量更新记录"""
        session = self.get_session()
        try:
            updated_count = 0
            
            for update_data in updates:
                if 'id' not in update_data:
                    continue
                
                id = update_data.pop('id')
                instance = session.query(self.model_class).filter(self.model_class.id == id).first()
                
                if instance:
                    for key, value in update_data.items():
                        if hasattr(instance, key):
                            setattr(instance, key, value)
                    updated_count += 1
            
            session.commit()
            return updated_count
        except Exception as e:
            session.rollback()
            raise e
        finally:
            session.close()
    
    def bulk_delete(self, ids: List[int]) -> int:
        """批量删除记录"""
        session = self.get_session()
        try:
            count = session.query(self.model_class).filter(self.model_class.id.in_(ids)).count()
            session.query(self.model_class).filter(self.model_class.id.in_(ids)).delete(synchronize_session=False)
            session.commit()
            return count
        except Exception as e:
            session.rollback()
            raise e
        finally:
            session.close()
    
    def get_statistics(self) -> Dict[str, Any]:
        """获取统计信息"""
        session = self.get_session()
        try:
            total_count = session.query(self.model_class).count()
            
            # 获取最新和最旧的记录
            latest = session.query(self.model_class).order_by(desc(self.model_class.created_at)).first()
            oldest = session.query(self.model_class).order_by(asc(self.model_class.created_at)).first()
            
            return {
                "total_count": total_count,
                "latest_created": latest.created_at if latest else None,
                "oldest_created": oldest.created_at if oldest else None,
                "table_name": self.model_class.__tablename__
            }
        finally:
            session.close()
    
    def paginate(self, page: int = 1, per_page: int = 20, **filters) -> Dict[str, Any]:
        """分页查询"""
        offset = (page - 1) * per_page
        
        # 获取总数
        total = self.count(**filters)
        
        # 获取当前页数据
        items = self.find(filters, limit=per_page, offset=offset)
        
        # 计算分页信息
        total_pages = (total + per_page - 1) // per_page
        has_prev = page > 1
        has_next = page < total_pages
        
        return {
            "items": items,
            "total": total,
            "page": page,
            "per_page": per_page,
            "total_pages": total_pages,
            "has_prev": has_prev,
            "has_next": has_next,
            "prev_page": page - 1 if has_prev else None,
            "next_page": page + 1 if has_next else None
        }
